package service;

import java.util.ArrayList;
import java.util.GregorianCalendar;
import java.util.List;

import model.DailyIrregular;
import model.DailyRegular;
import model.Drug;
import model.PN;
import model.Patient;

public class Service {
	private static Service instance = new Service();
	private List<Patient> patients;
	private List<Drug> drugs;

	/**
	 * Return the static instance of this class.
	 * @return Service
	 */
	public static Service getInstance() {
		return instance;
	}

	/**
	 * Creates a PN prescription
	 */
	public PN createPNPrescription(GregorianCalendar startDate,
			GregorianCalendar endDate, Patient patient, Drug drug, double count) {
		// Check if dates are valid.
		if (checkDates(startDate, endDate)) {
			PN pn = new PN(startDate, endDate, count); // Create a new prescription.
			pn.setDrug(drug); // Set the drug.
			patient.addPerson(pn); // Add the prescription to the patient.
			return pn;
		} else // If dates are invalid.
			throw new RuntimeException("Incorrect dates.");
	}

	/**
	 * Creates a DailyRegular prescription. 
	 */
	public DailyRegular createDailyRegularPrescription(
			GregorianCalendar startDate, GregorianCalendar endDate,
			Patient patient, Drug drug, double morningCount, double noonCount,
			double eveningCount, double nightCount) {
		// Check if dates are valid.
		if (checkDates(startDate, endDate)) {
			DailyRegular dailyRegular = new DailyRegular(startDate, endDate,
					morningCount, noonCount, eveningCount, nightCount); // Create a new prescription.
			dailyRegular.setDrug(drug); // Set the drug.
			patient.addPerson(dailyRegular); // Add the prescription to the patient.
			return dailyRegular;
		} else // If dates are invalid.
			throw new RuntimeException("Incorrect dates.");

	}

	/**
	 * Creates a DailyIrregular prescription.
	 */
	public DailyIrregular createDailyIrregularPrescription(
			GregorianCalendar startDate, GregorianCalendar endDate,
			Patient patient, Drug drug, String[] hours, double[] countOfUnits) {
		// Check if dates are valid.
		if (checkDates(startDate, endDate)) {
			DailyIrregular dailyIrregular = new DailyIrregular(startDate,
					endDate); // Create a new prescription.
			dailyIrregular.setDrug(drug); // Set the given drug for the prescription.
			// For each variable in the hours array, add a dose with the given hours and units.
			for (int i = 0; i < hours.length; i++)
				dailyIrregular.createDose(hours[i], countOfUnits[i]);
			patient.addPerson(dailyIrregular); // Add the prescription to the patient.
			return dailyIrregular;
		} else // If dates are invalid.
			throw new RuntimeException("Incorrect dates.");
	}
	
	/**
	 * Uses the PN prescription, adding a dose to it.
	 * Throws a RuntimeException, if the date is not in the correct interval 
	 * for the PN prescription.
	 */
	public void prescriptionPNUsed(PN prescription, GregorianCalendar date) {
		if (
			(date.after(prescription.getStartDate()) && date.before(prescription.getEndDate())) // if date is inbetween
			|| date.equals(prescription.getStartDate()) // or equal to startdate
			|| date.equals(prescription.getEndDate()) // or equal to enddate
			)
			prescription.addDose(date); // then add dose
		else
			throw new RuntimeException("Date is illegal.");
	}

	/**
	 * Returns the recommended dose for the patient (the dose depends on the weight of the patient).
	 */
	public double recommendedDosePrDay(Patient patient, Drug drug) {
		double result = 0;
		
		if (patient.getWeight() < 25) // If patient's weight is less than 25 kg.
			result = patient.getWeight() * drug.getUnitPrKgPrDayLight(); // Calculate using the light factor.
		else if (patient.getWeight() > 120) // If the patient's weight is more than 120 kg.
			result = patient.getWeight() * drug.getUnitPrKgPrDayHeavy(); // Calculate using the heavy factor.
		else // the Patient's weight must be >= 25 and <= 120 kg.
			result = patient.getWeight() * drug.getUnitPrKgPrDayNormal(); // Calculate using the normal factor.
		
		return result;
	}

	/**
	 * Returns the list of patients.
	 * @return List<Patient>
	 */
	public List<Patient> getPatients() {
		return patients;
	}

	/**
	 * Returns the list of drugs.
	 * @return List<Drug>
	 */
	public List<Drug> getDrugs() {
		return drugs;
	}
	
	/**
	 * Compare two dates and see if they are in the correct order.
	 */
	public boolean checkDates(GregorianCalendar firstDate, GregorianCalendar secondDate) {
		return (secondDate.after(firstDate) && firstDate.before(secondDate)) // if date is in correct order.
			|| firstDate.equals(secondDate); // or equal.
	}

	/**
	 * Initialize variables.
	 */
	public void startup() {
		patients = new ArrayList<Patient>();
		drugs = new ArrayList<Drug>();

		// -- The following is adding data for testing purposes.
		
		patients.add(new Patient("Jane Jensen", "121256-0512", 63.4));
		patients.add(new Patient("Finn Madsen", "070985-1153", 83.2));

		drugs.add(new Drug("Pinex", 0.1, 0.15, 0.16, "units"));
		drugs.add(new Drug("Paracetamol", 1, 1.5, 2, "ml"));
		drugs.add(new Drug("Fucidin", 0.025, 0.025, 0.025, "units"));
		drugs.add(new Drug("ABC", 0.01, 0.015, 0.02, "units"));

		createPNPrescription(new GregorianCalendar(2007, 3, 1), new GregorianCalendar(2007, 3, 12),
				patients.get(0), drugs.get(1), 123);
		createPNPrescription(new GregorianCalendar(2007, 3, 12),
				new GregorianCalendar(2007, 5, 12), patients.get(0), drugs.get(0), 3);

		createDailyRegularPrescription(new GregorianCalendar(2007, 1, 10), new GregorianCalendar(
				2007, 1, 12), patients.get(1), drugs.get(1), 2, -1, 1, -1);
		String[] kl = { "12:00", "12:40", "16:00", "18:45" };
		double[] an = { 0.5, 1, 2.5, 3 };
		createDailyIrregularPrescription(new GregorianCalendar(2007, 1, 23), new GregorianCalendar(
				2007, 1, 24), patients.get(1), drugs.get(2), kl, an);
		// --
	}

}
